和 D5 一樣手法,開一個無限猴子打字機的專案。
![]
這個 UI 用 SwiftUI 來做,是非常快的。下面這邊的程式碼,不含程式邏輯,單純 UI 排版。
struct InfiniteMonkeyTypingContentView: View {
@State private var targetText = ""
@State private var monkeyTyperCount = 1
@State private var logText = ""
@State private var textStyle = UIFont.TextStyle.body
private var targetHint: String {
if targetText.isEmpty {
return "目前沒目標,請輸入目標文字在輸入框"
}
return "你的目標為: \(targetText)"
}
var body: some View {
VStack {
Text("無限猴子打字機")
.font(.largeTitle)
.padding(.top, 20)
Text(targetHint)
.lineLimit(1)
.padding()
TextField("請輸入目標", text: $targetText)
.autocapitalization(.none)
.padding()
.textFieldStyle(.roundedBorder)
monkeyTyperStepper
monkeyActionButtons
monkeyLogsAndClearLogs
Rectangle()
.foregroundColor(.white)
.border(Color.blue)
.padding()
Spacer()
}
}
private var monkeyTyperStepper: some View {
HStack {
Stepper("猴子數: \(monkeyTyperCount)") {
stepperIncrease()
} onDecrement: {
stepperDecrease()
}
}
.padding()
}
private var monkeyActionButtons: some View {
HStack {
Button("猴子停手") {
// TODO: - 叫猴子停手
}
Button("叫猴子開始打字囉") {
// TODO: - 叫猴子們開始打字
}
}
.buttonStyle(.bordered)
.padding()
}
private var monkeyLogsAndClearLogs: some View {
HStack {
Spacer()
Text("猴子的打字紀錄")
Button {
// TODO: - 清掉打字
} label: {
Text("清除打字紀錄")
}
.padding(.leading, 20)
.buttonStyle(.bordered)
Spacer()
}
}
private func stepperIncrease() {
monkeyTyperCount += 1
}
private func stepperDecrease() {
if monkeyTyperCount > 1 {
monkeyTyperCount -= 1
}
}
}
上面的圖,是目標區沒有任何文字的 UI,如果我們打了一段字,UI 會提示我們目前的目標。就像下面這樣子。
打字紀錄區還未完成,下面這一段,事實上只是畫一個方形上去而已,這個 log 區有很多種做法。
Rectangle()
.foregroundColor(.white)
.border(Color.blue)
.padding()
在以前 UIKit 的時代,我會讓 log 噴到 UITextView 上。UITextView 的元件可以裝載非….常多非常多的文字,而且已經自帶上下捲動功能,在設定上非常方便。
而這個做法,在 SwiftUI 時代,仍然可以使用,用 UIViewRepresentable 就能做到。
這是用 List 上下可滑動的特性,binding 一個 string array 後,SwiftUI 框架會自動更新 View。如果這個 list 長度不長的話,我個人覺得不會遇到效能的問題。但這個 log 功能,通常是把最新的紀錄,放在最上面 (當然,放在最下面也可以,Xcode console 就是放在最下面,但他有附加一直滾動的功能)。
如果設計成放講 list 最上方,就會需要一直把 log insert 到第 0 個位置。目前是沒有試到效能瓶頸,但沒有優化的狀況下,最後一定要遇到瓶頸。
我們可以等遇到了再說,或是,給予這個 log array 一個容量,只要超過這個容量,就把最舊的紀錄丟到。